package GSEA::ES::EScalculator ;

use strict ;
use warnings;

sub constrEScalculator($$$$) #constructor
{
	my ($classe , $L_table , $S_table , $Pparameter ) = @_; 
	
	
	if( ! defined($L_table 	 )	){ die("argument 'L_table' is not set , error");}
	if( ! defined($S_table 	 )	){ die("argument 'S_table' is not set , error");}
	if( ! defined($Pparameter) 	){ die("argument 'Pparameter' is not set , error");}

	
	my $this = {
					"L_table"		=> $L_table		,
					"S_table"		=> $S_table		,
					"Pparameter"	=> $Pparameter	,					
					"common"		=> 0			,
					"distrib"		=> 0			,					
					"courb" 		=> 0			,
					"ESmax" 		=> 0			,
					"ESmin" 		=> 0
				};
	
	bless ($this,$classe);  
		
	return $this; 
}


sub searchCommonGenes($)  
{	
	(my $this ) = @_ ;
	 	
 	my @L_table = @{ $this->{"L_table"} } ;
 	my @S_table = @{ $this->{"S_table"} } ;
 	my @common	;
	
#	print("Searching common genes in the 2 lists ... ");
#	print("size of L list : ".($#L_table + 1)."\n");
#	print("size of S list : ".($#S_table + 1)."\n");

	for(my $i =0 ; $i< @L_table ;$i++)
	{
		my $gene_id = @{ $L_table[$i]  }[0] ;
		
		my $j = 0 ;
		
		while( ($j < @S_table) && ($S_table[$j] ne $gene_id)  )
		{
			$j++;
		}
		if( ($j < @S_table) && ($S_table[$j] eq $gene_id))
		{
			push(@common , [ @{ $L_table[$i]  }[0] , @{ $L_table[$i]  }[1] , $i ] );	
		}
		
		#print( ($i+1)." / ".@L_table."\n");
	}
	
	
#	print("\n\ncommon genes are : \n");
#	for(my $i =0 ; $i< @common ;$i++)
#	{
#		my $gene_id   = @{ $common[$i]  }[0] ;
#		my $gene_rank = @{ $common[$i]  }[1] ;
#		
#		print("gene=$gene_id  // rnak=$gene_rank \n ");
#	}
#
#	print("total hits=".@common."/".@L_table." \t\t total misses=".(@L_table-@common)."/".@L_table." \n");
	
	$this->{"common"} = \ @common ;
	return @common ; 
}


sub CalculateEScourb($) 
{
	(my $this ) = @_ ;
 	
 	my $power 		= $this->{"Pparameter"};
 	my @common		= @{ $this->{"common"} 	} ;
 	my @L_table 	= @{ $this->{"L_table"} } ;
 	my $L_tableSize = $#L_table + 1;
 	
	
 	my @ditrib ;
	my @courb = (0);
	my $ESsum = 0;
	my $ESmax = 0;
	my $ESmin = 0;
	
	#### Calculing  Total Hit number
		
	my $hit_sum = 0 ;
	for(my $i=0 ; $i < @common ; $i++)
	{
		my $pt = $common[$i];
		my $socre = ( @{$pt}[1] )** $power ; 
		$hit_sum += $socre ;
	}
	
	# if there is no common genes : 
	if(@common==0){return ( [0], [0], 0);}
		
	### Calculating ES
	my $cursor = 0 ;
	for( my $i = 0 ; $i < @common ; $i++  )
	{
		my $pt = $common[$i];
		
		my $gene_id	=  @{$pt}[0] ;
		my $score	=  @{$pt}[1] ;
		my $rank	=  @{$pt}[2] ;
				
		## doing the 'down section'
		for(my $j = $cursor ; $j < $rank ; $j++ )
		{
			# adding point to the courb	
			$ESsum -= 1 / ( $L_tableSize - @common ) ;
			push( @courb , $ESsum );
			
			# is it a max/min ?
			if( $ESmax < $ESsum ){ $ESmax = $ESsum ; }
			if( $ESmin > $ESsum ){ $ESmin = $ESsum ; }
			
			# updating the distribution
			push( @ditrib , 0 );
		}
		$cursor = $rank ;
		
		
		## adding the Hit point
		$score = ( $score )** $power  ; 
		$score = $score / $hit_sum ;
		
		# adding point to the courb		
		$ESsum += $score ; 
		push(@courb , $ESsum );
		
		# is it a max/min ?
		if( $ESmax < $ESsum ){ $ESmax = $ESsum ; }
		if( $ESmin > $ESsum ){ $ESmin = $ESsum ; }
		
		
		# updating the distribution
		push( @ditrib , 1 );
		
		$cursor++;
	}
	
	
	for( my $i = $cursor ; $i < $L_tableSize ; $i++  )
	{
		# adding point to the courb	
		$ESsum -= 1 / ( $L_tableSize - @common ) ;
		push( @courb , $ESsum );
		
		# is it a max/min ?
		if( $ESmax < $ESsum ){ $ESmax = $ESsum ; }
		if( $ESmin > $ESsum ){ $ESmin = $ESsum ; }
		
		# updating the distribution
		push( @ditrib , 0 );
	}
	
	# setting of the class's attributes
	$this->{"courb"} 	= \ @courb ;
	$this->{"distrib"} 	= \ @ditrib ;
	$this->{"ESmax"} 	= $ESmax ;
	$this->{"ESmin"} 	= $ESmin ;

return 0;
}


sub getHitMiss($)
{
	(my $this )= @_ ;
	
	
	if( $this->{"common"} == 0 ) 
	{
		$this->searchCommonGenes();
	}
	
	my @L_table = @{ $this->{"L_table"} };				
	my @common  = @{ $this->{"common"}  };		
					
	my $Nhit	= $#common + 1 ;
	my $Nmiss	= ( $#L_table + 1 ) - ( $Nhit ) ;
	
	return ( $Nmiss , $Nhit ) ;
}

sub getScores($)
{
	(my $this )= @_ ;
	
	
	if(  ( $this->{"ESmax"} ==  $this->{"ESmin"} )  )
	{
		if( $this->{"common"} == 0 ) 
		{
			$this->searchCommonGenes();
		}	
		
		$this->CalculateEScourb() ;	
	}
	
	my $ESmax = $this->{"ESmax"} ;
	my $ESmin = $this->{"ESmin"} ;
	
	return ( $ESmin , $ESmax ) ;
}

sub getCourb($)
{
	(my $this) = @_ ;
	
	$this->getScores();
	
	my $pt_courb = $this->{"courb"} ;
	my @courb    = @{ $pt_courb } ;
	
	return ( @courb ) ;
}

sub getDistribution($)
{
	(my $this )= @_ ;
	
	$this->getScores();
	
	my $pt_distrib = $this->{"distrib"} ;
	my @distrib    = @{ $pt_distrib } ;
	
	return ( @distrib ) ;
}


1;